<?php

namespace app\command\export;

use app\command\BaseCommand;
use app\common\utils\MyLog;
use think\console\Input;
use think\console\input\Argument;
use think\console\Output;

class ExportCustomerData extends BaseCommand
{
    protected $task_name = 'ExportCustomer';
    protected $task_desc = '客户数据导出';
    protected $export_file_name_prefix = 'ExportCustomer';
    protected $staff_id = 2677; //发送提醒通知的员工id
    protected $start_data_id; //起始的数据id,分批次导出会用到
    protected $end_data_id; //结束的数据id,分批次导出会用到
    protected $time;

    protected function configure()
    {
        $this->setName($this->task_name)
            ->addArgument('operate', Argument::REQUIRED, '操作类型: prepare/export/merge')
            ->addOption('batch_size', null, Argument::OPTIONAL, '分批次导出拆分的批次,用于计算start_data_id和end_data_id;比如:计划分为3批导出,就传3')
            ->addOption('start_data_id', null, Argument::OPTIONAL, '起始的数据id,分批次导出会用到')
            ->addOption('end_data_id', null, Argument::OPTIONAL, '结束的数据id,分批次导出会用到')
            ->addOption('merge_file_path', null, Argument::OPTIONAL, '需要合并的多个文件的绝对路径')
            ->setDescription($this->task_desc);
        $this->outputArgumentNotice();
    }

    protected function execute(Input $input, Output $output)
    {
        $operate = $input->getArgument('operate');
        if ($operate == 'prepare') {  //准备工作
            $this->executePrepare($input, $output);
        } elseif ($operate == 'export') {  //导出
            $this->executeExport($input, $output);
        } elseif ($operate == 'merge') {  //合并
            $this->executeMerge($input, $output);
        } else {
            P("operate参数传值错误,请查看使用说明");
        }
    }

    // 准备工作
    protected function executePrepare(Input $input, Output $output)
    {
        $batch_size = $input->getOption('batch_size');
        $base_where = [
            ['type', '<>', 3],
        ];

        if (empty($batch_size)) {
            PE('现在要开始计算start_data_id(起始的数据id)和end_data_id(结束的数据id),需要手动传入 "--batch_size=xxx(拆分的批次)" 用来计算这两个参数');
        }

        //计算批次
        //$total_count = Customer::where($base_where)->count();
        $total_count = 35; //mock数据
        $batch_limit = ceil($total_count / $batch_size);
        P("数据总数{$total_count},分为{$batch_size}批次处理,每批次处理{$batch_limit}条数据");

        $batch_data_ids = []; //获取分批次的每一批次的id
        $last_id = 0; // 上一批次最后的 id，作为下一批次的起始点
        $check_sql = [];
        $check_batch_count = [];
        $loop_index = 1;
        do {
            // 查询当前批次的数据 id（跳过 type = 3）
            /*
            $data_ids = Customer::where($base_where)
                ->where([
                    ['id', '>', $last_id], // 大于上一批次的最后一个 id
                ])->order('id', 'asc')
                ->limit($batch_limit)
                ->column('id');
            */
            $data_ids = []; //mock数据

            // 打印当前 SQL 调试（可选）
            //P(Customer::getLastSql());

            if (!empty($data_ids)) {
                $min_id = $data_ids[0];
                $max_id = end($data_ids);
                $batch_data_ids[] = implode(',', [$min_id, $max_id]);
                $_item_check_count = 10; //mock数据
                /*
                $_item_check_count = Customer::where($base_where)
                    ->where([
                        ['id', '>=', $min_id],
                        ['id', '<=', $max_id],
                    ])->count();
                */
                $check_batch_count[] = $_item_check_count;
                $check_sql[] = "[第{$loop_index}批次]" . /*Customer::sql() .*/
                    "; 总数:{$_item_check_count}";
                $loop_index++;
                $last_id = $max_id; // 更新 last_id 为当前批次最大 id
            } else {
                $last_id = 0; // 结束循环
            }
        } while (!empty($data_ids));
        //PE($batch_data_ids);

        //$_check_all_count = Customer::where($base_where)->count();
        //$check_sql[] = "[查询总数]" . Customer::sql() . "; 总数:{$_check_all_count}";
        $_check_all_count = 0; //mock数据

        P("根据目前导出数据的情况,每批次处理{$batch_limit}条数据,已计算的批次如下:\n" . implode(' | ', $batch_data_ids));
        P("验证结果的SQL如下,请执行验证一下总数是否正确:");
        P(implode("\n", $check_sql));
        P("[验证结果] 所有批次的总数相加的结果:" . array_sum($check_batch_count) . "; 和验证的总数 {$_check_all_count} 是否相等?");
        var_dump(array_sum($check_batch_count) == $_check_all_count);
        exit;
    }

    // 执行导出逻辑
    protected function executeExport(Input $input, Output $output)
    {
        $start_data_id = $input->getOption('start_data_id');
        $end_data_id = $input->getOption('end_data_id');
        if (empty($start_data_id) || empty($end_data_id)) {
            P('分批次导出,需要手动传入 "--start_data_id=xxx(起始的数据id)" 和 "--end_data_id=xxx(结束的数据id)" ');
            exit;
        }
        $this->start_data_id = $start_data_id;
        $this->end_data_id = $end_data_id;
        $this->time = date("Ymd_His", time());

        //$notice_staff_qw_uid = Staff::where(['id' => $this->staff_id])->value('qywx_userid');
        $notice_staff_qw_uid = 'RenXing'; //mock数据
        try {
            //获取总数,计算总页数
            $page_size = 10; //每页处理多少条数据,为了方便调试,这里先写的小一点,生产环境下可以改为100或者更大值
            $count = 35; //mock数据,改为查询数据总数
            $total_page = ceil($count / $page_size);
            $prefix_msg = $this->task_desc . ", dataId:从{$this->start_data_id}到{$this->end_data_id}, 每页处理{$page_size}条数据, 数据总数{$count}, 共{$total_page}页 ";
            P(date('Y-m-d H:i:s', time()) . ' | ' . $prefix_msg);

            //发送企微消息
            $notice_size = 5; //每隔多少页给企微发送一次进度提醒,为了方便调试,这里先写的小一点,生产环境下可以改为50或者更大值
            //发送企微消息
            //QwMessage::init()->sendMarkDown($notice_staff_qw_uid, echoDate() . '| ' . $prefix_msg . "; 接下来,每隔{$notice_size}页会发送一次企微通知进度.");

            //分页,循环处理数据
            $first_page = 1; //从第几页开始
            for ($page = $first_page; $page <= $total_page; $page++) {
                try {
                    $res = $this->_handleDataList($page, $page_size);
                    $notice_msg = date('Y-m-d H:i:s', time()) . " | 当前第{$page}页处理结果: " . $res;
                } catch (\Exception $for_e) {
                    //循环内当前页的异常情况处理
                    MyLog::writeExceptionLog($for_e, "{$this->task_name}_dataId_{$this->start_data_id}_{$this->end_data_id}_page_{$page}");
                    $notice_msg = date('Y-m-d H:i:s', time()) . ' | ' . $prefix_msg . " | 当前第{$page}页处理结果出现异常: " . $for_e->getMessage();
                    //QwMessage::init()->sendMarkDown($notice_staff_qw_uid, $notice_msg); //发送企微消息
                }

                //每一页处理完后打印结果,并根据$notice_size判断是否发送企微进度
                P($notice_msg);
                if ($page % $notice_size == 0) {
                    //QwMessage::init()->sendMarkDown($notice_staff_qw_uid, $notice_msg); //发送企微消息
                }
                sleep(3);
            }
            $notice_msg = date('Y-m-d H:i:s', time()) . ' | ' . $prefix_msg . " | 全部导出完成";
            //QwMessage::init()->sendMarkDown($notice_staff_qw_uid, $notice_msg); //发送企微消息
        } catch (\Exception $e) {
            //整体异常情况处理
            $notice_msg = date('Y-m-d H:i:s', time()) . ' | ' . $this->task_desc . ": 出现异常,已终止,详情请查看log.异常信息:" . $e->getMessage();
            //QwMessage::init()->sendMarkDown($notice_staff_qw_uid, $notice_msg); //发送企微消息
            MyLog::printExceptionLogAndExit($e);
        }
    }

    protected function _handleDataList($page, $page_size)
    {
        $customer_list = []; //todo 这里改为查库,整合数据

        $file_folder = 'export_excel/' . date("Y/m", time()) . '/' . $this->export_file_name_prefix . '_' . $this->time;
        $file_path = root_path() . 'public/' . $file_folder;
        $page_str = self::formatToFiveDigits($page);
        $file_name = "{$this->export_file_name_prefix}_dataId_{$this->start_data_id}_{$this->end_data_id}_page_{$page_str}";
        if ($page != 1) {
            //ExcelService::$skip_title = true; //不是第1页,则跳过表头
        }
        //$output_file_name = ExcelService::outputExcel($format_list, $field_map, $file_path, $file_name, false);
        return $file_name;
    }

    public static function formatToFiveDigits(int $number): string
    {
        return str_pad((string)$number, 5, '0', STR_PAD_LEFT);
    }


    // 执行合并逻辑
    protected function executeMerge(Input $input, Output $output)
    {
        $merge_file_path = $input->getOption('merge_file_path');
        if (empty($merge_file_path)) {
            PE("合并的时候,需要指定第二个参数: --merge_file_path=需要合并的多个文件的绝对路径");
        }
        if (!is_dir($merge_file_path)) {
            PE("目录不存在");
        }
        $mergeRes = mergeExcel($merge_file_path, $this->task_desc . '.xlsx');
        var_dump($mergeRes);
    }

}
